/*
 * @Author: Suo-Yuheng syh15399227325@163.com
 * @Date: 2025-08-31 17:32:09
 * @LastEditors: Suo-Yuheng syh15399227325@163.com
 * @LastEditTime: 2025-08-31 22:04:51
 * @FilePath: /0831/blockqueue/BlockQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

template <class T>
class BlockQueue
{
    static const int defalutnum = 20; // ?
public:
    BlockQueue(int maxcap = defalutnum)
        : _maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        // _low_water = _maxcap / 2;
        // _high_water = (_maxcap * 2) / 3;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);

        while (_q.size() == _maxcap) // 判断本身就是在访问临界资源
        {
            pthread_cond_wait(&_p_cond, &_mutex); // 调用时 自动释放锁
        }

        // 走到这里 1、队列没满  2、被唤醒了
        _q.push(in); // 阻塞队列，不是想生产就能生产的, 需要先确保生产条件满足
        pthread_cond_signal(&_c_cond); // 生产者走到这里，一定能保证 队列里 有数据

        // if (_q.size() > _high_water)    // 生产超过 高水位线，唤醒消费者
        // {
        //     pthread_cond_signal(&_c_cond); // 生产者走到这里，一定能保证 队列里 有数据
        // }
        // pthread_cond_signal(&_c_cond); // 生产者走到这里，一定能保证 队列里 有数据

        pthread_mutex_unlock(&_mutex);
    }

    // 生产或者 消费的同时，可能多个线程同时执行，需要对共享资源、临界区 进行保护 —— 加锁
    // 保证同步 ——  条件变量

    T pop()
    {
        pthread_mutex_lock(&_mutex);

        while (_q.size() == 0) // 等待条件，如果没有 产品，就等待去
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }

        // 走到这里， 1、队列非空  2、被唤醒了
        T out = _q.front();
        _q.pop();                   // 阻塞队列，先确保消费条件满足
        pthread_cond_signal(&_p_cond); // 消费者走到这里，一定能保证 队列里 有空间，唤醒生产者生产
        
        // if (_q.size() < _low_water) // 低于 低水位线，唤醒生产者
        // {
        //     pthread_cond_signal(&_p_cond); // 消费者走到这里，一定能保证 队列里 有空间，唤醒生产者生产
        // }
        // pthread_cond_signal(&_p_cond);  // 消费者走到这里，一定能保证 队列里 有空间，唤醒生产者生产

        pthread_mutex_unlock(&_mutex);
        return out;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

private:
    std::queue<T> _q; // 共享资源
    int _maxcap;      // 队列中的极值
    // int _mincap;    // 队列中的极值
    pthread_mutex_t _mutex; // 保护
    pthread_cond_t _c_cond; // 同步 消费者
    pthread_cond_t _p_cond; // 同步 生产者

    // int _low_water;  // 水位线，就是 预警，如果低于 低水位线，就要开始生产
    // int _high_water; // 如果 高于 高水位线，就要让消费者消费
                     // 如果在 低水位线 —— 高水位线 之间，让 他们 自由运行
};